]
Terminate conditional expressions or lists
TLDR
View documentation for the [ keyword
SYNOPSIS
[ expression ]
PARAMETERS
-b FILE
True if FILE exists and is a block special file.
-c FILE
True if FILE exists and is a character special file.
-d FILE
True if FILE exists and is a directory.
-e FILE
True if FILE exists (regardless of type).
-f FILE
True if FILE exists and is a regular file.
-g FILE
True if FILE exists and its set-group-ID bit is set.
-k FILE
True if FILE exists and its 'sticky' bit is set.
-L FILE
True if FILE exists and is a symbolic link.
-p FILE
True if FILE exists and is a named pipe (FIFO).
-r FILE
True if FILE exists and read permission is granted.
-s FILE
True if FILE exists and has a size greater than zero.
-t FD
True if file descriptor FD is open and refers to a terminal (defaults to 1, stdout).
-u FILE
True if FILE exists and its set-user-ID bit is set.
-w FILE
True if FILE exists and write permission is granted.
-x FILE
True if FILE exists and execute permission is granted.
-O FILE
True if FILE exists and is owned by the effective user ID.
-G FILE
True if FILE exists and is owned by the effective group ID.
-N FILE
True if FILE exists and has been modified since it was last read.
FILE1 -nt FILE2
True if FILE1 is newer (modification time) than FILE2.
FILE1 -ot FILE2
True if FILE1 is older (modification time) than FILE2.
FILE1 -ef FILE2
True if FILE1 and FILE2 refer to the same device and inode numbers (hard link).
-z STRING
True if the length of STRING is zero.
-n STRING
True if the length of STRING is non-zero.
STRING
True if STRING is not empty (non-zero length).
STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.
INT1 -eq INT2
True if INT1 is equal to INT2.
INT1 -ne INT2
True if INT1 is not equal to INT2.
INT1 -ge INT2
True if INT1 is greater than or equal to INT2.
INT1 -gt INT2
True if INT1 is greater than INT2.
INT1 -le INT2
True if INT1 is less than or equal to INT2.
INT1 -lt INT2
True if INT1 is less than INT2.
! EXPR
True if EXPR is false (logical NOT).
EXPR1 -a EXPR2
True if both EXPR1 and EXPR2 are true (logical AND).
EXPR1 -o EXPR2
True if either EXPR1 or EXPR2 is true (logical OR).
DESCRIPTION
The ']' character, when used in the context of a Linux command, is primarily the required closing bracket for the '[' command. The '[' command is a synonym for the 'test' command, which evaluates conditional expressions. It is not a standalone command but rather a syntactic requirement that signifies the end of the expression to be evaluated by the 'test' utility.
When writing shell scripts, the '[' command is used to perform various checks, such as verifying file existence, comparing strings, or evaluating numerical conditions. The closing ']' acts as a mandatory delimiter, completing the command's syntax. Without this closing ']', the shell would report a syntax error or an unmatched bracket error, as the command interpreter expects it to properly delimit the conditional expression. Its primary purpose is to make the conditional expression visually resemble a mathematical or programming language bracketed expression, improving readability and ensuring correct parsing by the shell.
CAVEATS
The ']' character is not a standalone command; it functions purely as the closing argument for the '[' (test) command. It must be provided as a separate argument, meaning a space is required before it. For example, `[ -f myfile ]` is correct, while `[-f myfile]` or `[ -f myfile]` would result in errors due to incorrect parsing by the shell.
Additionally, variable expansions within '[ ... ]' are subject to word splitting and pathname expansion, which can lead to unexpected behavior if variables are not properly quoted (e.g., `[ "$VAR" = "value" ]`). Modern shells often provide enhanced conditional constructs like '[[ ... ]]' which mitigate these issues.
USAGE AS A COMMAND
It's crucial to understand that '[' is an actual command (usually a hard link to 'test' or a shell built-in), and ']' is simply its final argument. The shell parses '[' as the command name and everything up to ']' as its arguments. The ']' character itself doesn't execute anything; it serves as a required marker for the end of the conditional expression.
SPACING REQUIREMENT
A common pitfall for beginners is forgetting the spaces around the '[' and ']' characters. Because they are treated as separate arguments by the shell, `[ -f file ]` is correct, but `[-f file]` or `[ -f file]` will cause errors as the shell tries to interpret them differently (e.g., `[-f` as a single command name or missing arguments).
COMPARISON WITH <I>[[ ... ]]</I>
Modern shells like Bash, Zsh, and Ksh provide an extended conditional command `[[ ... ]]`. This `[[` construct is a keyword rather than a command, offering several advantages over `[ ... ]`: it prevents word splitting and pathname expansion on unquoted variables, allows for regular expression matching (`=~`), and supports C-style logical operators (`&&`, `||`). For new scripts, `[[ ... ]]` is generally recommended for its robustness and enhanced features.
HISTORY
The 'test' command, for which '[' is a synonym and ']' is the required closing delimiter, is a fundamental part of Unix-like operating systems. It originated in the early versions of Unix and was standardized by POSIX (Portable Operating System Interface) to ensure consistent behavior across different systems. Its purpose is to perform conditional checks essential for scripting, such as checking file attributes or comparing values. The bracketed syntax `[ ... ]` was introduced for syntactic sugar, making conditional expressions resemble those in programming languages, thereby enhancing readability.